const { Component } = React;

class LeafAA extends Component {
  /**
   * 构造函数
   * 用于组件内部的state初始化、事件方法的绑定
   * @param {*} props
   * @param {*} context
   */
  constructor(props, context) {
    console.log("AA", "step", 1, "constructor begin");
    //避免构造方法后面的代码使用this.props时出现undefined错误
    super(props, context);

    //在构造方法内对state应直接进行赋值，而不应调用setState()方法
    //避免拷贝props到state中，而要用this.props.xxx , 否则当props发生变化时，state将不能得到及时更新
    this.state = {
      label: "leaf AA",
      toChild: "",
      stampStatus: "",
      num1: 0
    };
    console.log("AA", "step", 2, "constructor end");
  }

  /**
   * getDerivedStateFromProps
   * 它允许组件根据props的变化而更新其内部state。如果要更新state，
   * 该方法必须返回新的state（称之为派生state)，或者返回null代表不更新。
   * 这个生命周期方法在render方法执行之前被调用，
   * 当组件在mount和updating时都会执行该方法。
   * @param {*} props
   * @param {*} state
   */
  static getDerivedStateFromProps(props, state) {
    console.log("AA", "step", 3, "getDerivedStateFromProps begin");
    const { stamp, toChild } = props;
    let newState = null;
    //在组件的生命周期中，派生state应该谨慎使用，
    //应当在满足当props改变并符合一定的条件时再对state进行更新
    //当组件的setState方法和forceUpdate方法被调用时，也会触发该生命周期方法
    if (stamp > 500) {
      newState = Object.assign(state, {
        toChild,
        stampStatus: "大于500"
      });
    } else {
      newState = Object.assign(state, {
        toChild,
        stampStatus: "小于500"
      });
    }
    console.log("AA", "step", 4, "getDerivedStateFromProps end");
    return newState;
  }

  /**
   * shouldComponentUpdate
   * 该生命周期方法决定当组件的props和state发生改变时，
   * 是否需要重新渲染组件。该方法默认情况下返回true，
   * 表示需要重新渲染，可以通过返回false阻止组件的向
   * 下的生命周期方法的执行。该生命周期方法应该仅作
   * 为**性能优化**的手段去使用，而避免用于其他用途。
   * @param {*} nextProps
   * @param {*} nextState
   */
  shouldComponentUpdate(nextProps, nextState) {
    //当组件的props发生改变或者setState方法执行后会触发该生命周期方法的调用。
    //在组件的mount阶段和forceUpdate()方法执行后，不会触发该生命周期方法调用。
    //可以考虑让组件继承React.PureComponent,  其已经实现了React.PureComponent方法，
    //不过它的实现是对当props和state和nextProps和nextState的浅层比较

    console.log("AA", "step", 99, "shouldComponentUpdate start");
    const { stamp } = nextProps;
    console.log("AA", "step", 99, "shouldComponentUpdate end");
    return stamp > 0;
  }

  /**
   * getSnapshotBeforeUpdate
   * 该方法在render方法之后，在render的输出到DOM之前执行。
   * 在这个生命周期方内允许组件可以从DOM上捕获一些信息
   * （例如 scroll position），该方法返回的任何值都将作
   * 为参数（后称快照值）传递给componentDidUpdate()生
   * 命周期方法。该方法要么返回一个快照值或者null 。
   * @param {*} prevProps
   * @param {*} prevState
   */
  getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log("AA", "step", 99, "getSnapshotBeforeUpdate start");
    console.log("AA", "step", 99, "getSnapshotBeforeUpdate end");
    return {
      stamp: prevProps.stamp
    };
  }

  componentDidCatch(error, info) {
    console.log("AA", "step", 99, "componentDidCatch start");
    console.log(error, info);
    console.log("AA", "step", 99, "componentDidCatch end");
  }

  //WARNING! To be deprecated in React v17. Use componentDidMount instead.
  // componentWillMount() {
  //   console.log("AA", "step", 99, "componentWillMount start");
  //   console.log("AA", "step", 99, "componentWillMount end");
  // }

  componentDidMount() {
    console.log("AA", "step", 99, "componentDidMount start");
    // let node = this.getDOMNode();
    console.log("AA", "step", 99, "componentDidMount end");
  }

  //WARNING! To be deprecated in React v17. Use componentDidUpdate instead.
  // componentWillUpdate(nextProps, nextState) {
  //   console.log("AA", "step", 99, "componentWillUpdate start");
  //   console.log("AA", "step", 99, "componentWillUpdate end");
  // }
  componentDidUpdate(nextProps, nextState) {
    console.log("AA", "step", 99, "componentDidUpdate start");
    console.log("AA", "step", 99, "componentDidUpdate end");
  }

  componentWillUnmount() {
    console.log("AA", "step", 99, "componentWillUnmount start");
    console.log("AA", "step", 99, "componentWillUnmount end");
  }

  render() {
    console.log("AA", "step", 5, "render begin");
    const { label, stampStatus, toChild, num1 } = this.state;
    const { visible } = this.props;
    console.log("AA", "step", 6, "render end");
    return (
      <div style={{ display: visible ? "block" : "none" }}>
        <div>label:{label}</div>
        <div>toChild:{toChild}</div>
        <div>stampStatus:{stampStatus}</div>
        <div>num1:{num1}</div>
        <div>
          <button onClick={() => this.setState({ num1: num1 + 1 })}>
            num1 +1
          </button>
        </div>
      </div>
    );
  }
}
